﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Routing;
using Nop.Core.Infrastructure;
using Nop.Core.Plugins;

namespace Nop.Web.Framework.Mvc.Routes
{
    /// <summary>
    /// Route publisher
    ///  路由发布 用来实现对插件的启动地址进行注册
    /// </summary>
    public class RoutePublisher : IRoutePublisher
    {

        /// <summary>
        /// 基于反射的程序集查询变量器
        /// </summary>
        protected readonly ITypeFinder typeFinder;

        /// <summary>
        /// Ctor
        /// 基于依赖注入的IOC容器 在系统启动的时候 进行所有接口实例的初始化工作
        /// 系统启动的时候  使用Nop.Web.Framework 中 的DependencyRegistrar进行注册接口的实例
        /// </summary>
        /// <param name="typeFinder"></param>
        public RoutePublisher(ITypeFinder typeFinder)
        {
            this.typeFinder = typeFinder;
        }

        /// <summary>
        /// Find a plugin descriptor by some type which is located into its assembly
        /// 通过插件的 实现类Type信息 获取指定的插件的描述信息
        /// </summary>
        /// <param name="providerType">Provider type</param>
        /// <returns>Plugin descriptor</returns>
        protected virtual PluginDescriptor FindPlugin(Type providerType)
        {
            if (providerType == null)
                throw new ArgumentNullException("providerType");

            //遍历所有在系统中注册的插件 
            foreach (var plugin in PluginManager.ReferencedPlugins)
            {
                if (plugin.ReferencedAssembly == null)
                    continue;

                ///如果插件的程序集与要寻找的目标程序集名称相同 则判定为索要找的插件DLL
                if (plugin.ReferencedAssembly.FullName == providerType.Assembly.FullName)
                    return plugin;
            }

            return null;
        }

        /// <summary>
        /// Register routes
        /// 注册路由  想当前程序中注册插件中的发布的路由  也就是URL访问地址
        /// </summary>
        /// <param name="routes">Routes  当前系统中的路由集合对象（也就是当前APP中的所有的Routes集合）</param>
        public virtual void RegisterRoutes(RouteCollection routes)
        {
            ///遍历程序集   查询所有实现此接口的DLL  中的Class
            var routeProviderTypes = typeFinder.FindClassesOfType<IRouteProvider>();


            var routeProviders = new List<IRouteProvider>();
            foreach (var providerType in routeProviderTypes)
            {
                //Ignore not installed plugins忽略未安装的插件
                var plugin = FindPlugin(providerType);
                if (plugin != null && !plugin.Installed)
                    continue;

                ///根据指定的Type   使用Activator  反射出此Type 的实例 Instance
                var provider = Activator.CreateInstance(providerType) as IRouteProvider;
                routeProviders.Add(provider);
            }

            //对插件的优先级进行排序
            routeProviders = routeProviders.OrderByDescending(rp => rp.Priority).ToList();
            routeProviders.ForEach(//传递一个Action委托  使用Lambda表达式构建匿名函数  参数为IEnumerable 中的单个元素类型，可迭代的强类型元素的实例被作为参数传递到函数块中
                (rp) => 
                { 
                    //执行此代码块   来对每个插件中的发布路由类 执行注册路由指令
                    rp.RegisterRoutes(routes);
                }
                );
        }
    }
}
